package cn.ciis.basic.config;

import cn.ciis.basic.base.BaseCache;
import cn.ciis.basic.directive.PatchDriective;
import cn.ciis.basic.interceptor.LoginSessionInterceptor;
import cn.ciis.basic.kit.CiisKit;
import cn.ciis.basic.kit.DruidKit;
import cn.ciis.basic.kit.J2CacheKit;
import cn.ciis.basic.model.Enterprise;
import cn.ciis.basic.model.Equipment;
import cn.ciis.basic.model._MappingKit;
import cn.ciis.basic.plugin.CiisPlugs;
import cn.ciis.basic.plugin.J2CachePlugin;
import cn.ciis.basic.plugin.KissoJfinalPlugin;
import cn.ciis.basic.routes.CiisRoutes;
import cn.ciis.basic.routes.FrontRoutes;
import cn.ciis.basic.routes.SysRoutes;
import cn.ciis.basic.websocket.AuthorityWebSocket;
import cn.ciis.sys.permission.PermissionDirective;
import cn.ciis.sys.role.RoleDirective;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.wall.WallFilter;
import com.cybermkd.mongo.plugin.MongoJFinalPlugin;
import com.jfinal.config.*;
import com.jfinal.json.MixedJsonFactory;
import com.jfinal.kit.LogKit;
import com.jfinal.kit.Prop;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.druid.DruidPlugin;
import com.jfinal.template.Engine;
import net.dreamlu.event.EventPlugin;
import net.dreamlu.event.EventThreadFactory;

import java.util.List;
import java.util.concurrent.Executors;

/**
 * @author 冉志林
 */
public class CiisConfig extends JFinalConfig {
    /**
     * 使用 jfinal-undertow 时此处仅保留声明，不能有加载代码
     */
    public static Prop p;

    private WallFilter wallFilter;

    private static SymmetricCrypto aes;

    public static CiisPlugs tioPlugs=null;

    public static Prop loadConfig() {
        if (p == null) {
            try {
                p = PropKit.use("ciis-dev.properties");
            }catch (Exception e){
                LogKit.error("没有找到配置文件ciis-dev.properties");
            }
        }

        if(p == null || !p.getBoolean("devMode",false)){
            if (p == null){
                p = PropKit.use("ciis-pro.properties");
            }else{
                p.appendIfExists("ciis-pro.properties");
            }

        }
        p.appendIfExists("config/ciis.setting");
        final String AES_KEY="Z*dTjvtU4t7yY27Y5be78weGEB@rPxtV";

        if(null == aes){
            //随机生成密钥
            byte[] key = AES_KEY.getBytes();
            //构建
            aes = new SymmetricCrypto(SymmetricAlgorithm.AES, key);
        }
        return null;
    }

    @Override
    public void configConstant(Constants me) {
        loadConfig();
        me.setDevMode(p.getBoolean("devMode", false));
        me.setJsonFactory(MixedJsonFactory.me());

        me.setError404View("/_view/404.html");

        // 支持 Controller、Interceptor、Validator 之中使用 @Inject 注入业务层，并且自动实现 AOP
        me.setInjectDependency(true);

        // 是否对超类中的属性进行注入
        me.setInjectSuperClass(true);
        // 添加了注入Proxy 动态代理,4.6 版本新增//解决云端发布报错
        me.setToCglibProxyFactory();
        me.setToSlf4jLogFactory();
    }

    @Override
    public void configRoute(Routes me) {
        me.add(new FrontRoutes());
        me.add(new SysRoutes());//系统
        me.add(new CiisRoutes());//灌溉
    }

    /**
     * 配置模板引擎，通常情况只需配置共享的模板函数
     */
    @Override
    public void configEngine(Engine me) {
        me.setDevMode(p.getBoolean("engineDevMode", false));

        me.setCompressorOn();//压缩html
        // 添加角色、权限指令
        me.addDirective("role", RoleDirective.class);
        me.addDirective("permission", PermissionDirective.class);
        me.addDirective("patch", PatchDriective.class);

        me.addSharedFunction("/_view/_admin/common/__admin_layout.html");
        me.addSharedFunction("/_view/_admin/common/_admin_paginate.html");
        me.addSharedFunction("/_view/_admin/common/_card_index.html");
        me.addSharedFunction("/_view/_admin/common/_card_add_edit.html");
        me.addSharedFunction("/_view/_admin/common/_card.html");
        me.addSharedFunction("/_view/_admin/common/_card_tree.html");
        me.addSharedFunction("/_view/_admin/common/_card_maintain.html");
    }

    public static DruidPlugin getDruidPlugin() {
        if(p == null){
            loadConfig();
        }

        String jdbcUrl = p.get("mysql.url", "").trim();
        if(p.getBoolean("uselessMode",true) || !jdbcUrl.startsWith("jdbc:mysql")){//数据库配置进行了加密

            return new DruidPlugin(decryptStr(p.get("mysql.url")), decryptStr(p.get("mysql.user")), decryptStr(p.get("mysql.password")));
        }else{
            if(p.getBoolean("devMode", false)){
                LogKit.info("数据库jdbcUrl加密结果:{}",encryptHex(p.get("mysql.url")));
                LogKit.info("数据库user加密结果:{}",encryptHex(p.get("mysql.user")));
                LogKit.info("数据库password加密结果:{}",encryptHex(p.get("mysql.password")));
            }

            return new DruidPlugin(p.get("mysql.url"), p.get("mysql.user"), p.get("mysql.password"));
        }
    }

    public static MongoJFinalPlugin getMongoPlugin(){
        MongoJFinalPlugin mjp = new MongoJFinalPlugin();

        if(p.getBoolean("uselessMode",true)){
            mjp.add(decryptStr(p.get("mongo.url")), Convert.toInt(decryptStr(p.get("mongo.port"))));
            mjp.setDatabase(decryptStr(p.get("mongo.database")));
            mjp.auth(decryptStr(p.get("mongo.userName")),decryptStr(p.get("mongo.pwd")));
        }else{

            if(p.getBoolean("devMode", false)){
                LogKit.info("mongoDB服务器地址加密结果:{}",encryptHex(p.get("mongo.url")));
                LogKit.info("mongoDB服务器端口加密结果:{}",encryptHex(p.get("mongo.port")));
                LogKit.info("mongoDB服务器数据库名加密结果:{}",encryptHex(p.get("mongo.database")));
                LogKit.info("mongoDB服务器用户名加密结果:{}",encryptHex(p.get("mongo.userName")));
                LogKit.info("mongoDB服务器密码加密结果:{}",encryptHex(p.get("mongo.pwd")));
            }
            mjp.add(p.get("mongo.url"),p.getInt("mongo.port"));
            mjp.setDatabase(p.get("mongo.database"));
            mjp.auth(p.get("mongo.userName"),p.get("mongo.pwd"));
        }
       return mjp;
    }

    @Override
    public void configPlugin(Plugins me) {
        DruidPlugin druidPlugin = getDruidPlugin();
        // 加强数据库安全
        wallFilter = new WallFilter();
        wallFilter.setDbType("mysql");
        druidPlugin.addFilter(wallFilter);
        // 添加 StatFilter 才会有统计数据
        druidPlugin.addFilter(new StatFilter());
        me.add(druidPlugin);

        ActiveRecordPlugin arp = new ActiveRecordPlugin(druidPlugin);
       // arp.setTransactionLevel(Connection.TRANSACTION_READ_COMMITTED);
        _MappingKit.mapping(arp);
        me.add(arp);
        arp.setShowSql(p.getBoolean("devMode", false));

        arp.getEngine().setToClassPathSourceFactory();
        arp.addSqlTemplate("/sql/_all_sqls.sql");
        //mongoDb数据库
        if (StrKit.notBlank(p.get("mongo.url"))) {
            me.add(getMongoPlugin());
        }
        //缓存
        //me.add(new EhCachePlugin());

        //事件监听插件
        EventPlugin eventPlugin = new EventPlugin();
        if(p.getBoolean("devMode",false)){
            eventPlugin.enableClassScan();
            eventPlugin.scanPackage("cn.ciis");//指定需要扫描的包
        }
        //启用自定义线程池，防止单线程阻塞
        eventPlugin.threadPool(Executors.newCachedThreadPool(new EventThreadFactory()));
        eventPlugin.async();//开启异步
        me.add(eventPlugin);

        /*tcp通讯*/
        if (p.getBoolean("ciisEnabled", false)) {
            tioPlugs = new CiisPlugs();

            tioPlugs.setClassScan(true);//自动扫描handler
            tioPlugs.setScanPackage("cn.ciis.server.handler;cn.ciis.server.client");//要扫描的包
            me.add(tioPlugs);
        }
        me.add(new J2CachePlugin());//缓存框架
        me.add(new KissoJfinalPlugin());//单点登录插件
    }

    @Override
    public void configInterceptor(Interceptors me) {

        me.add(new LoginSessionInterceptor());
    }

    @Override
    public void configHandler(Handlers me) {
        // druid 统计页面功能
        me.add(DruidKit.getDruidStatViewHandler());
    }

    @Override
    public void onStart() {
        // 让 druid 允许在 sql 中使用 union
        wallFilter.getConfig().setSelectUnionCheck(false);
        //定时任务
        // 支持秒
        //CronUtil.setMatchSecond(true);
        // 定时任务
        //CronUtil.start();
        ThreadUtil.execAsync(new Runnable() {
            @Override
            public void run() {
                List<Enterprise> enterprises = Enterprise.dao.find("SELECT * FROM ciis_enterprise WHERE isDel=0 ");
                if (!enterprises.isEmpty()){

                    enterprises.forEach(enterprise -> {
                        J2CacheKit.set(BaseCache.ENTERPRISE_TIMED_CACHE,enterprise.getCode(),enterprise);
                    });
                }
                List<Equipment> equipment = Equipment.dao.find("SELECT * FROM ciis_equipment WHERE isDel=0");
                if (!equipment.isEmpty()){

                    equipment.forEach(equipment1 -> {
                        J2CacheKit.set(BaseCache.EQUIPMENT_TIMED_CACHE,equipment1.getCode(),equipment1);
                    });
                }
            }
        });

        //生成静态资源的随机版本号。避免js、css文件更新以后，避免浏览器缓存导致更新无效果
        CiisKit.RESOURCE_VERSION=RandomUtil.randomString(7);
//        EventKit.post(new OnStartEvent());
    }

    @Override
    public void onStop() {

        AuthorityWebSocket.closeAll(null);
        super.onStop();
    }

    public static String encryptHex(String content) {
        //加密为16进制表示
        return aes.encryptHex(content);
    }

    /**
     * AES解密
     */
    public static String decryptStr(String encryptHex){
        //解密为字符串
        return aes.decryptStr(encryptHex, CharsetUtil.CHARSET_UTF_8);
    }

}
